package com.mall.mymall.aspect;

import com.mall.mymall.common.Result;
import com.mall.mymall.dao.dto.AdminDto;
import com.mall.mymall.dao.entity.Users;
import com.mall.mymall.enums.Roles;
import com.mall.mymall.utils.JwtTokenProvider;
import com.mall.mymall.utils.RedisUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * 用于给成功的登录请求统一发放token
 * 由于security的过滤器链只在到达真实访问资源之前生效 特地创建这个Aop类
 */
@Aspect
@Component
public class IssueTokenAspect {
    @Autowired
    private JwtTokenProvider jwtProvider;

    @Autowired
    private RedisUtils redisUtils;

    @AfterReturning(pointcut = "execution(public * com.mall.mymall.controller.AdministratorsController.login(..))",
            returning = "retVal")
    public void afterAdminUserLogin(JoinPoint joinPoint, Object retVal) throws Throwable {
        handleLoginSuccess(retVal,"admin");
    }

    @AfterReturning(pointcut = "execution(public * com.mall.mymall.controller.UsersController.login(..))",returning = "resultVal")
    public void afterUserLogin(JoinPoint joinPoint,Object resultVal) throws Throwable {
        handleLoginSuccess(resultVal,"user");

    }

    private void handleLoginSuccess(Object result, String userType) throws Throwable {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Result<?> resultObj = (Result<?>) result;

        if (resultObj.getCode() == 200) {
            Object userObject = resultObj.getData();
            if (userObject == null) {
                throw new IllegalArgumentException("User object is null");
            }

            String username;
            int roleId;

            if ("admin".equals(userType)) {
                AdminDto adminDto = (AdminDto) userObject;
                username = adminDto.getUsername();
                roleId = adminDto.getRoleId();
                redisUtils.saveUser(username, adminDto);
            } else if ("user".equals(userType)) {
                Users user = (Users) userObject;
                username = user.getUsername();
                roleId = user.getRoleId();
                redisUtils.saveUser(username, user);
            } else {
                throw new IllegalArgumentException("Invalid user type: " + userType);
            }

            // 生成token
            String token = jwtProvider.generateToken(username);

            // 获取HttpServletResponse
            HttpServletResponse response = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();
            assert response != null;

            // 根据是否为匿名用户，处理权限和token
            if (authentication == null || "anonymousUser".equals(authentication.getName())) {
                // 赋予角色权限
                List<GrantedAuthority> authorities = Roles.IssueRole(roleId);
                authentication = new UsernamePasswordAuthenticationToken(username, null, authorities);
                SecurityContextHolder.getContext().setAuthentication(authentication);
            } else {
                // 如果用户已经认证，直接使用当前认证信息
                username = authentication.getPrincipal().toString();
                token = jwtProvider.generateToken(username);
            }

            // 设置Authorization头
            response.setHeader("Authorization", "Bearer " + userType + " " + token);
        }
    }
}
